﻿
// SerialAssistantDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "SerialAssistant.h"
#include "SerialAssistantDlg.h"
#include "afxdialogex.h"
#include "ChartCtrl/ChartCtrl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#pragma warning(disable : 4996)

LPVOID CSerialAssistantDlg::threadPara = NULL;
int CSerialAssistantDlg::isRunningIMU = 0;
int CSerialAssistantDlg::isRunningGPS = 0;

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
public:
	DECLARE_MESSAGE_MAP()
	afx_msg void OnBnClickedOk();
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

// CSerialAssistantDlg 对话框



CSerialAssistantDlg::CSerialAssistantDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_SERIALASSISTANT_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDI_ICO_NWPU);
}

BEGIN_MESSAGE_MAP(CSerialAssistantDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_CBN_SELCHANGE(IDC_COMBO_COM, &CSerialAssistantDlg::OnSelchangeComboCom)
	ON_CBN_SELCHANGE(IDC_COMBO_BDR, &CSerialAssistantDlg::OnSelchangeComboBdr)
	ON_CBN_SELCHANGE(IDC_COMBO_CHECKBIT, &CSerialAssistantDlg::OnSelchangeComboCheckbit)
	ON_CBN_SELCHANGE(IDC_COMBO_STOPBIT, &CSerialAssistantDlg::OnSelchangeComboStopbit)
	ON_BN_CLICKED(IDC_BTN_OPENSER, &CSerialAssistantDlg::OnClickedBtnOpenser)
	ON_BN_CLICKED(IDC_BTN_EXIT, &CSerialAssistantDlg::OnClickedBtnExit)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BTN_PAUSE, &CSerialAssistantDlg::OnClickedBtnPause)
	ON_BN_CLICKED(IDC_BTN_SETZERO, &CSerialAssistantDlg::OnClickedBtnSetzero)
	ON_MESSAGE(WM_SERIALMSG, &CSerialAssistantDlg::OnSerialMsg)		// 串口对象消息
	ON_MESSAGE(WM_DATAERRMSG, &CSerialAssistantDlg::OnDataErrMsg)	// 数据异常消息
	ON_COMMAND(ID_APP_ABOUT, &CSerialAssistantDlg::OnAppAbout)
	ON_CBN_SELCHANGE(IDC_COMBO_COM_G, &CSerialAssistantDlg::OnCbnSelchangeComboComG)
	ON_CBN_SELCHANGE(IDC_COMBO_BDR_G, &CSerialAssistantDlg::OnCbnSelchangeComboBdrG)
	ON_CBN_SELCHANGE(IDC_COMBO_STOPBIT_G, &CSerialAssistantDlg::OnCbnSelchangeComboStopbitG)
	ON_CBN_SELCHANGE(IDC_COMBO_CHECKBIT_G, &CSerialAssistantDlg::OnCbnSelchangeComboCheckbitG)
	ON_BN_CLICKED(IDC_CHECK_GPGGA, &CSerialAssistantDlg::OnBnClickedCheckGpgga)
END_MESSAGE_MAP()


// CSerialAssistantDlg 消息处理程序

BOOL CSerialAssistantDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// 禁用系统关闭按钮
	CMenu* pMenu = this->GetSystemMenu(FALSE);				//系统菜单
	pMenu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);	//禁用关闭按钮

	// Combobox初始化代码
	ComB_com.SetCurSel(0);
	ComB_bdr.SetCurSel(4);
	ComB_stopbit.SetCurSel(0);
	ComB_checkbit.SetCurSel(0);
	Comb_com_g.SetCurSel(1);
	Comb_bdr_g.SetCurSel(2);
	Comb_stp_g.SetCurSel(0);
	Comb_chk_g.SetCurSel(0);

	// 定时器设置
	SetLocalTime();
	SetTimer(1, 1000, 0);
	SetTimer(2, 1000, 0);

	// 初始化List
	int ListColIdx = 0;
	ListData.InsertColumn(ListColIdx++, _T("计数"),		  LVCFMT_CENTER, 60);
	ListData.InsertColumn(ListColIdx++, _T("Gx (deg/s)"), LVCFMT_CENTER, 120);
	ListData.InsertColumn(ListColIdx++, _T("Gy (deg/s)"), LVCFMT_CENTER, 120);
	ListData.InsertColumn(ListColIdx++, _T("Gz (deg/s)"), LVCFMT_CENTER, 120);
	ListData.InsertColumn(ListColIdx++, _T("Ax (m/s^2)"), LVCFMT_CENTER, 120);
	ListData.InsertColumn(ListColIdx++, _T("Ay (m/s^2)"), LVCFMT_CENTER, 120);
	ListData.InsertColumn(ListColIdx++, _T("Az (m/s^2)"), LVCFMT_CENTER, 120);

	ListColIdx = 0;
	ListDataGPS.InsertColumn(ListColIdx++, _T("UTC"),     LVCFMT_CENTER, 95);
	ListDataGPS.InsertColumn(ListColIdx++, _T("Vh m/s"),  LVCFMT_CENTER, 100);
	ListDataGPS.InsertColumn(ListColIdx++, _T("Heading"), LVCFMT_CENTER, 100);
	ListDataGPS.InsertColumn(ListColIdx++, _T("Vu m/s"),  LVCFMT_CENTER, 100);
	ListDataGPS.InsertColumn(ListColIdx++, _T("Lat deg"), LVCFMT_CENTER, 125);
	ListDataGPS.InsertColumn(ListColIdx++, _T("Lng deg"), LVCFMT_CENTER, 125);
	ListDataGPS.InsertColumn(ListColIdx++, _T("Alt m"), LVCFMT_CENTER, 125);

	// 串口对象初始化
	rcvCounter = 1;
	mySerial = SerialPort();
	SerialParaInit();		// 根据窗口初始设置，初始化串口参数
	mySerial.hwndOfComm = (AfxGetMainWnd())->m_hWnd;
	
	checkGPGGA.SetCheck(1);

	// 图像初始化
	CChartAxis* pAxis_g = NULL, *pAxis_a = NULL;
	pAxis_g = m_Chart_gyro.CreateStandardAxis(CChartCtrl::BottomAxis);		// 坐标系初始化（不可缺少）
	pAxis_g->SetAutomatic(true);
	pAxis_g = m_Chart_gyro.CreateStandardAxis(CChartCtrl::LeftAxis);
	pAxis_g->SetAutomatic(true);
	pAxis_a = m_Chart_acc.CreateStandardAxis(CChartCtrl::BottomAxis);
	pAxis_a->SetAutomatic(true);
	pAxis_a = m_Chart_acc.CreateStandardAxis(CChartCtrl::LeftAxis);
	pAxis_a->SetAutomatic(true);

	TChartString chartTitle;
	chartTitle = _T("陀螺仪输出");
	m_Chart_gyro.GetTitle()->AddString(chartTitle);
	chartTitle = _T("加速度计输出");
	m_Chart_acc.GetTitle()->AddString(chartTitle);

	
	for (int i = 0; i < LineLen; i++)
	{
		data_t[i] = -20 + i * 0.1;
		data_gx[i] = 0;
		data_gy[i] = 0;
		data_gz[i] = 0;
		data_ax[i] = 0;
		data_ay[i] = 0;
		data_az[i] = 0;
	}
	m_Chart_gyro.RemoveAllSeries();	//先清空
	m_Chart_acc.RemoveAllSeries();	//先清空
	pLS_gx = m_Chart_gyro.CreateLineSerie();
	pLS_gy = m_Chart_gyro.CreateLineSerie();
	pLS_gz = m_Chart_gyro.CreateLineSerie();
	pLS_ax = m_Chart_acc.CreateLineSerie();
	pLS_ay = m_Chart_acc.CreateLineSerie();
	pLS_az = m_Chart_acc.CreateLineSerie();
	pLS_gx->SetPoints(data_t, data_gx, LineLen);
	pLS_gy->SetPoints(data_t, data_gy, LineLen);
	pLS_gz->SetPoints(data_t, data_gz, LineLen);
	pLS_ax->SetPoints(data_t, data_ax, LineLen);
	pLS_ay->SetPoints(data_t, data_ay, LineLen);
	pLS_az->SetPoints(data_t, data_az, LineLen);
	pLS_gy->SetColor(rgb_BLUE);				// Blue is y-axis
	pLS_gz->SetColor(rgb_GREEN);			// Green is z-axis
	pLS_ay->SetColor(rgb_BLUE);
	pLS_az->SetColor(rgb_GREEN);

	// GPS
	GPGGAOK = FALSE;
	BESTVELOK = FALSE;
	isRunningMsg = FALSE;

	// LOG Init
	editLog.SetWindowTextW(_T("软件启动"));

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CSerialAssistantDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

//  如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CSerialAssistantDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CSerialAssistantDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// 串口对象消息处理函数
LRESULT CSerialAssistantDlg::OnSerialMsg(WPARAM wParam, LPARAM lParam)
{
	if (isRunningMsg)
	{
		mySerial.isResolving = TRUE;		// 正在解析数据
		unsigned int msg_code = *(unsigned int*)wParam;
		char fileLine[1024];
		if (msg_code == mySerial.msg_getpkg)
		{
			unsigned char CHK;
			memcpy(pkgbuffer, mySerial.buffer[mySerial.buftagR], mySerial.pkgLen);		// 主线获取数据
			SYSCNT++;			// 以IMU采样为基础的计数时间戳
			CHK = (unsigned char)RcvChk();
			/*memcpy(&imudata.counter, &pkgbuffer[0], sizeof(unsigned char));
			memcpy(&imudata.CS, &pkgbuffer[1], sizeof(char));
			memcpy(&imudata.Ax, &pkgbuffer[2], sizeof(int));
			memcpy(&imudata.Ay, &pkgbuffer[6], sizeof(int));
			memcpy(&imudata.Az, &pkgbuffer[10], sizeof(int));
			memcpy(&imudata.Gx, &pkgbuffer[14], sizeof(int));
			memcpy(&imudata.Gy, &pkgbuffer[18], sizeof(int));
			memcpy(&imudata.Gz, &pkgbuffer[22], sizeof(int));
			memcpy(&imudata.Fx, &pkgbuffer[26], sizeof(int));
			memcpy(&imudata.Fy, &pkgbuffer[30], sizeof(int));
			memcpy(&imudata.Fz, &pkgbuffer[34], sizeof(int));
			memcpy(&imudata.Wx, &pkgbuffer[38], sizeof(int));
			memcpy(&imudata.Wy, &pkgbuffer[42], sizeof(int));
			memcpy(&imudata.Wz, &pkgbuffer[46], sizeof(int));*/
			/*imudata.wx = imudata.Wx / (float)100000.0;
			imudata.wy = imudata.Wy / (float)100000.0;
			imudata.wz = imudata.Wz / (float)100000.0;
			imudata.fx = imudata.Fx / (float)100000.0;
			imudata.fy = imudata.Fy / (float)100000.0;
			imudata.fz = imudata.Fz / (float)100000.0;*/

			memcpy(((char*)&imudata.Wx) + 3, &pkgbuffer[1 - 1], sizeof(char));
			memcpy(((char*)&imudata.Wx) + 2, &pkgbuffer[2 - 1], sizeof(char));
			memcpy(((char*)&imudata.Wx) + 1, &pkgbuffer[3 - 1], sizeof(char));
			*(((char*)&imudata.Wx) + 0) = 0;
			memcpy(((char*)&imudata.Wy) + 3, &pkgbuffer[4 - 1], sizeof(char));
			memcpy(((char*)&imudata.Wy) + 2, &pkgbuffer[5 - 1], sizeof(char));
			memcpy(((char*)&imudata.Wy) + 1, &pkgbuffer[6 - 1], sizeof(char));
			*(((char*)&imudata.Wy) + 0) = 0;
			memcpy(((char*)&imudata.Wz) + 3, &pkgbuffer[7 - 1], sizeof(char));
			memcpy(((char*)&imudata.Wz) + 2, &pkgbuffer[8 - 1], sizeof(char));
			memcpy(((char*)&imudata.Wz) + 1, &pkgbuffer[9 - 1], sizeof(char));
			*(((char*)&imudata.Wz) + 0) = 0;

			memcpy(((char*)&imudata.Fx) + 3, &pkgbuffer[11 - 1], sizeof(char));
			memcpy(((char*)&imudata.Fx) + 2, &pkgbuffer[12 - 1], sizeof(char));
			memcpy(((char*)&imudata.Fx) + 1, &pkgbuffer[13 - 1], sizeof(char));
			*(((char*)&imudata.Fx) + 0) = 0;
			memcpy(((char*)&imudata.Fy) + 3, &pkgbuffer[14 - 1], sizeof(char));
			memcpy(((char*)&imudata.Fy) + 2, &pkgbuffer[15 - 1], sizeof(char));
			memcpy(((char*)&imudata.Fy) + 1, &pkgbuffer[16 - 1], sizeof(char));
			*(((char*)&imudata.Fy) + 0) = 0;
			memcpy(((char*)&imudata.Fz) + 3, &pkgbuffer[17 - 1], sizeof(char));
			memcpy(((char*)&imudata.Fz) + 2, &pkgbuffer[18 - 1], sizeof(char));
			memcpy(((char*)&imudata.Fz) + 1, &pkgbuffer[19 - 1], sizeof(char));
			*(((char*)&imudata.Fz) + 0) = 0;

			imudata.wx = imudata.Wx / 256 * (float)0.00006103515625;
			imudata.wy = imudata.Wy / 256 * (float)0.00006103515625;
			imudata.wz = imudata.Wz / 256 * (float)0.00006103515625;
			imudata.fx = imudata.Fx / 256 * (float)0.00006103515625;
			imudata.fy = imudata.Fy / 256 * (float)0.00006103515625;
			imudata.fz = imudata.Fz / 256 * (float)0.00006103515625;

			// 将数据加入折线图并刷新(0.2s)
			if (rcvCounter % 25 == 0)
			{
				tk = tk + 0.1;
				addSample(tk, imudata);
				pLS_gx->SetPoints(data_t, data_gx, LineLen);
				pLS_gy->SetPoints(data_t, data_gy, LineLen);
				pLS_gz->SetPoints(data_t, data_gz, LineLen);
				pLS_ax->SetPoints(data_t, data_ax, LineLen);
				pLS_ay->SetPoints(data_t, data_ay, LineLen);
				pLS_az->SetPoints(data_t, data_az, LineLen);
			}

			/*if (CHK == FALSE)
			{
				SendMessage(WM_DATAERRMSG, (WPARAM)&msg_errchkfaile, (LPARAM)&SYSCNT);
			}*/

			// Write Data 2 IMUFile
			sprintf(fileLine, "%d %d %d %d %d %d %d %d %d %f %f %f %f %f %f ", SYSCNT, imudata.counter, CHK, imudata.Wx, imudata.Wy, imudata.Wz,
				imudata.Fx, imudata.Fy, imudata.Fz, imudata.wx, imudata.wy, imudata.wz, imudata.fx, imudata.fy, imudata.fz);
			fprintf(dataFile, fileLine);
			fflush(dataFile);

			if (GPGGAOK && BESTVELOK)
			{
				sprintf(fileLine, "1 %.3f %lf %lf %lf %d %lf %lf %f %d %d %f\n", gpgga.time, bestvel.vel_h, bestvel.heading,
					bestvel.vel_v, bestvel.SS, gpgga.Lat, gpgga.Lng, (gpgga.Alt+gpgga.Herr), gpgga.state, gpgga.SatNum, gpgga.HDOP);
				fprintf(dataFile, fileLine);
				fflush(dataFile);
				ListDataGPS.AddGPSItem(gpgga, bestvel);
				GPGGAOK = FALSE;
				BESTVELOK = FALSE;
			}
			else
			{
				fprintf(dataFile, "0 0 0 0 0 0 0 0 0 0 0 0\n");
				fflush(dataFile);
			}

			fprintf(ComDataFile, "93 ");
			for (size_t i = 0; i < mySerial.pkgLen; i++)
			{
				fprintf(ComDataFile, "%02X ", pkgbuffer[i]);
			}
			fprintf(ComDataFile, "\n");

			// 每1s插入一次数据
			if ((rcvCounter++) % 125 == 0)
			{
				ListData.AddIMUItem(imudata);
			}
		}
		else if (msg_code == mySerial.msg_getpkgfail)
		{
			MessageBox(_T("串口数据读取异常"), _T("通信异常"), MB_ICONWARNING);
		}
		else if (msg_code == mySerial.msg_getGPGGA)	// GPS数据处理函数
		{
			int pkglen = lParam;		// 从消息中获取数据长度

			memcpy(pkgbufferG0, mySerial.gpsbuffer0, pkglen);		// 主线获取数据
			sscanf_s(pkgbufferG0, ",%f,%lf,%c,%lf,%c,%hd,%hd,%f,%f,M,%f,M,%f,%hd*%hd\r",
				&gpgga.time, &gpgga.Lat, &gpgga.NS,1, &gpgga.Lng, &gpgga.WE,1, &gpgga.state, &gpgga.SatNum, &gpgga.HDOP,
				&gpgga.Alt, &gpgga.Herr, &gpgga.xx, &gpgga.BaseNum, &gpgga.chk);
			GPGGAOK = TRUE;
			sprintf(fileLine, "$GPGGA%s", pkgbufferG0);
			fprintf(GPSFile, fileLine);
			fflush(GPSFile);
		}
		else if (msg_code == mySerial.msg_getBESTVEL)
		{
			int pkglen = lParam;		// 从消息中获取数据长度

			memcpy(pkgbufferG0, mySerial.gpsbuffer1, pkglen);		// 主线获取数据
			sscanf_s(pkgbufferG0, ",%[^;];%[^,],%[^,],%f,%f,%lf,%lf,%lf,%f*%s\r",
				bestvel.header,128, bestvel.SOL_STATUS,32, bestvel.VEL_TYPE,32, &bestvel.latency, &bestvel.age, &bestvel.vel_h,
				&bestvel.heading, &bestvel.vel_v, &bestvel.xx, bestvel.CRC,16);

			if (!strcmp(bestvel.SOL_STATUS, "SOL_COMPUTED"))
				bestvel.SS = 0;
			else if (!strcmp(bestvel.SOL_STATUS, "INSUFFICIENT_OBS"))
				bestvel.SS = 1;
			else if (!strcmp(bestvel.SOL_STATUS, "NO_CONVERGENCE"))
				bestvel.SS = 2;
			else if (!strcmp(bestvel.SOL_STATUS, "COV_TRACE"))
				bestvel.SS = 3;

			BESTVELOK = TRUE;
			sprintf(fileLine, "#BESTVELA%s", pkgbufferG0);
			fprintf(GPSFile, fileLine);
			fflush(GPSFile);
		}
		mySerial.isResolving = FALSE;		// 一包数据解析完毕
	}
	return LRESULT();
}

LRESULT CSerialAssistantDlg::OnDataErrMsg(WPARAM wParam, LPARAM lParam)
{
	if (isRunningMsg)
	{
		mySerial.isResolving = TRUE;		// 正在解析数据
		unsigned int msg_code = *(unsigned int*)wParam;
		double t_err = (*(unsigned int*)lParam) * 0.0025;
		char logMsg[512];
		wchar_t wide[1024];
		int num;
		if (msg_code == msg_errlost)
		{
			editLog.SetWindowTextW(_T(" "));
			sprintf_s(logMsg, "第%.2fs惯导数据丢失，建议检查线路连接并重新开始数据采集。", t_err);
			num = MultiByteToWideChar(0, 0, logMsg, -1, NULL, 0);
			MultiByteToWideChar(0, 0, logMsg, -1, wide, num);
			editLog.SetWindowTextW(wide);
		}
		else if (msg_code == msg_errchkfaile)
		{
			sprintf_s(logMsg, "第%.2fs惯导数据校验未通过。", t_err);
			num = MultiByteToWideChar(0, 0, logMsg, -1, NULL, 0);
			MultiByteToWideChar(0, 0, logMsg, -1, wide, num);
			editLog.SetWindowTextW(wide);
		}
	}
	return LRESULT();
}



void CSerialAssistantDlg::OnSelchangeComboCom()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = ComB_com.GetCurSel();
	CString lab, lab10("\\\\.\\");
	ComB_com.GetLBText(idx, lab);
	if (idx >= 9)
	{
		lab = lab10 +  lab;
	}
	mySerial.ComNum = lab;
}


void CSerialAssistantDlg::OnSelchangeComboBdr()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = ComB_bdr.GetCurSel();
	CString lab;
	ComB_bdr.GetLBText(idx, lab);
	mySerial.bdr = _ttoi(lab);
}


void CSerialAssistantDlg::OnSelchangeComboCheckbit()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = ComB_checkbit.GetCurSel();
	mySerial.checkb = idx;
}


void CSerialAssistantDlg::OnSelchangeComboStopbit()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = ComB_stopbit.GetCurSel();
	mySerial.stopb = idx;
}

// 打开串口 按钮动作
void CSerialAssistantDlg::OnClickedBtnOpenser()
{
	int openRes;
	char fileName[64] = "";
	exitCode = 0;
	if (!mySerial.isOpen)
	{
		// ============================= IMU 串口打开 ======================================= //
		openRes = mySerial.OpenCOM();
		SYSCNT = 0;			// 系统计数重新清零
		if (openRes == 0)
		{
			// Initial File Work
			BtnOpen.SetWindowText(_T("关闭串口"));
			mySerial.isIMUOpen = TRUE;
			sprintf(fileName, "IMU_%4d%02d%02d%02d%02d%02d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
			dataFile = fopen(fileName, "w");
			sprintf(fileName, "COM_%4d%02d%02d%02d%02d%02d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
			ComDataFile = fopen(fileName, "w");
			if (dataFile == NULL || ComDataFile == NULL)
			{
				MessageBox(_T("IMU数据文件建立失败！"), _T("Warrning"), MB_OK);
			}
			else
			{
				fprintf(dataFile, "%% SOL_STATUS: 0-SOL_COMPUTED; 1-INSUFFICIENT_OBS; 2-NO_CONVERGENCE; 3-COV_TRACE\n");
				fprintf(dataFile, "%% GPS STATUS: 0-定位不可用或无效; 1-单点定位; 2-伪距差分; 4-RTK 固定解; 5-RTK 浮点解; 7-自定义位置\n");
				fprintf(dataFile, "%% FIMU计数 陀螺脉冲数 加计脉冲数 角速度 加速度 GPS更新　UTC　V_h Heading V_v SOL_STATUS Lat Lng Alt Status Sats HDOP\n");
			}
			// Create Thread
			threadPara = (LPVOID) &mySerial;
			isRunningIMU = 1;
			TP_CommThread = CreateThread(NULL, 0, SerialThread, threadPara, THREAD_PRIORITY_NORMAL, 0);
			ComB_com.EnableWindow(FALSE);		// 设置串口参数不可更改
			ComB_bdr.EnableWindow(FALSE);
			ComB_checkbit.EnableWindow(FALSE);
			ComB_stopbit.EnableWindow(FALSE);
			checkGPGGA.EnableWindow(FALSE);
		}
		else
		{
			MessageBox(_T("IMU串口打开失败！"), _T("Warrning"), MB_OK);
		}
		// ============================= GPS 串口打开 ======================================= //
		openRes = mySerial.OpenGPSCOM();
		if (openRes == 0)
		{
			// Initial File Work
			BtnOpen.SetWindowText(_T("关闭串口"));
			mySerial.isOpen = TRUE;
			mySerial.isGPSOpen = TRUE;
			sprintf(fileName, "GPS_%4d%02d%02d%02d%02d%02d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
			GPSFile = fopen(fileName, "w");
			if (GPSFile == NULL)
			{
				MessageBox(_T("GPS数据文件建立失败！"), _T("Warrning"), MB_OK);
			}
			// Create Thread
			threadPara = (LPVOID)&mySerial;
			isRunningGPS = 1;
			GPS_CommThread = CreateThread(NULL, 0, SerialThreadGPS, threadPara, THREAD_PRIORITY_NORMAL, 0);
			Comb_com_g.EnableWindow(FALSE);
			Comb_bdr_g.EnableWindow(FALSE);
			Comb_stp_g.EnableWindow(FALSE);
			Comb_chk_g.EnableWindow(FALSE);
			checkGPGGA.EnableWindow(FALSE);
		}
		else
		{
			MessageBox(_T("GPS串口打开失败！"), _T("Warrning"), MB_OK);
		}
		mySerial.isOpen = mySerial.isIMUOpen || mySerial.isGPSOpen;
		isRunningMsg = mySerial.isIMUOpen || mySerial.isGPSOpen;
	}
	else
	{
		int rtn = MessageBox(_T("数据采集中，确定要关闭串口？"), _T("工作中"), MB_OKCANCEL);
		if (rtn == IDOK)
		{
			BOOL isCloseThreadIMU, isCloseThreadGPS;
			isRunningMsg = FALSE;
			if (mySerial.isGPSOpen == TRUE)
			{
				mySerial.isGPSOpen = FALSE;
				isRunningGPS = 0;
				isCloseThreadGPS = CloseHandle(GPS_CommThread);
				if (!isCloseThreadGPS)
				{
					int rtn = MessageBox(_T("GPS串口线程结束异常，是否强制关闭？"), _T("串口关闭异常"), MB_OKCANCEL);
					if (rtn == IDOK)
					{
						CloseHandle(GPS_CommThread);
					}
				}
				mySerial.CloseGPSCOM();				// 关闭串口
				fflush(GPSFile);
				fclose(GPSFile);
				fflush(GPSFile);
				fclose(GPSFile);
				mySerial.isGPSOpen = FALSE;
				Comb_com_g.EnableWindow(TRUE);
				Comb_bdr_g.EnableWindow(TRUE);
				Comb_stp_g.EnableWindow(TRUE);
				Comb_chk_g.EnableWindow(TRUE);
				checkGPGGA.EnableWindow(TRUE);
			}

			if (mySerial.isIMUOpen == TRUE)
			{
				mySerial.isIMUOpen = FALSE;
				isRunningIMU = 0;
				isCloseThreadIMU = CloseHandle(TP_CommThread);
				if (!isCloseThreadIMU)
				{
					int rtn = MessageBox(_T("IMU串口线程结束异常，是否强制关闭？"), _T("串口关闭异常"), MB_OKCANCEL);
					if (rtn == IDOK)
					{
						CloseHandle(TP_CommThread);
					}
				}
				mySerial.CloseCOM();				// 关闭串口
				fflush(dataFile);
				fclose(dataFile);
				fflush(ComDataFile);
				fclose(ComDataFile);
				ComB_com.EnableWindow(TRUE);		// 设置串口参数可更改
				ComB_bdr.EnableWindow(TRUE);
				ComB_checkbit.EnableWindow(TRUE);
				ComB_stopbit.EnableWindow(TRUE);
				checkGPGGA.EnableWindow(TRUE);
			}
			BtnOpen.SetWindowText(_T("打开串口"));
			mySerial.isOpen = FALSE;
		}
	}
}


void CSerialAssistantDlg::OnClickedBtnExit()
{
	int ok_cancel;
	// TODO: 在此添加控件通知处理程序代码
	if (mySerial.isOpen == TRUE)
	{
		ok_cancel = MessageBox(_T("串口处于打开状态，是否继续退出程序？"), _T("Warrning"), MB_OKCANCEL);
		if (ok_cancel == 0)
		{
			BtnOpen.SetWindowText(_T("打开串口"));
			mySerial.isOpen = FALSE;
			CloseHandle(TP_CommThread);
			mySerial.CloseCOM();		// 关闭串口
			fflush(dataFile);
			fclose(dataFile);
			EndDialog(0);
		}
	}
	else
	{
		EndDialog(0);
	}
}


void CSerialAssistantDlg::DoDataExchange(CDataExchange* pDX)
{
	// TODO: 在此添加专用代码和/或调用基类

	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_COMBO_COM, ComB_com);
	DDX_Control(pDX, IDC_COMBO_BDR, ComB_bdr);
	DDX_Control(pDX, IDC_COMBO_STOPBIT, ComB_stopbit);
	DDX_Control(pDX, IDC_COMBO_CHECKBIT, ComB_checkbit);
	DDX_Control(pDX, IDC_EDIT_DAY, Timer_day);
	DDX_Control(pDX, IDC_EDIT_HOUR, Timer_hour);
	DDX_Control(pDX, IDC_EDIT_MINUTE, Timer_minute);
	DDX_Control(pDX, IDC_EDIT_MOUNTH, Timer_month);
	DDX_Control(pDX, IDC_EDIT_SECOND, Timer_second);
	DDX_Control(pDX, IDC_EDIT_YEAR, Timer_year);
	DDX_Control(pDX, IDC_EDIT_COUNTER, EditCounter);
	DDX_Control(pDX, IDC_BTN_PAUSE, BtnPause);
	DDX_Control(pDX, IDC_LIST_DATA, ListData);
	DDX_Control(pDX, IDC_LIST_GPS, ListDataGPS);
	DDX_Control(pDX, IDC_BTN_OPENSER, BtnOpen);
	DDX_Control(pDX, IDC_BTN_EXIT, BtnExit);
	DDX_Control(pDX, IDC_CHART_GYRO, m_Chart_gyro);
	DDX_Control(pDX, IDC_CHART_ACC, m_Chart_acc);
	DDX_Control(pDX, IDC_COMBO_COM_G, Comb_com_g);
	DDX_Control(pDX, IDC_COMBO_BDR_G, Comb_bdr_g);
	DDX_Control(pDX, IDC_COMBO_STOPBIT_G, Comb_stp_g);
	DDX_Control(pDX, IDC_COMBO_CHECKBIT_G, Comb_chk_g);
	DDX_Control(pDX, IDC_EDIT_LOG, editLog);
	DDX_Control(pDX, IDC_CHECK_GPGGA, checkGPGGA);
}

void CSerialAssistantDlg::addSample(double tk, IMUData imudata)
{
	int i;
	for (i=0; i < LineLen-1; i++)
	{
		data_t[i] = data_t[i + 1];
		data_gx[i] = data_gx[i + 1];
		data_gy[i] = data_gy[i + 1];
		data_gz[i] = data_gz[i + 1];
		data_ax[i] = data_ax[i + 1];
		data_ay[i] = data_ay[i + 1];
		data_az[i] = data_az[i + 1];
	}
	data_t[i] = tk;
	data_gx[i] = imudata.wx;
	data_gy[i] = imudata.wy;
	data_gz[i] = imudata.wz;
	data_ax[i] = imudata.fx;
	data_ay[i] = imudata.fy;
	data_az[i] = imudata.fz;
}

// 数据包求和校验
BOOL CSerialAssistantDlg::RcvChk()
{
	unsigned char i, chkref,  chksum = 0;
	for (i = 0; i < mySerial.pkgLen; i++)
	{
		chksum += pkgbuffer[i];
	}
	chkref = pkgbuffer[1];
	chksum = chksum - chkref + 255;		// 减去校验和加上帧头数据
	if (chksum == chkref)
		return TRUE;
	else
		return FALSE;
}

// 定时处理程序
void CSerialAssistantDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch (nIDEvent)
	{
	case 1:
		SetLocalTime();
		break;
	case 2:
		if ((!counterPause) && mySerial.isOpen)
		{
			time_tmp.Format(_T("%4d"), ++secCounter);
			EditCounter.SetText(time_tmp);
		}
		break;
	}
	CDialogEx::OnTimer(nIDEvent);
}

void CSerialAssistantDlg::SetLocalTime()
{
	GetLocalTime(&st);
	time_tmp.Format(_T("%4d"), st.wYear);
	Timer_year.SetText(time_tmp);
	time_tmp.Format(_T("%2d"), st.wMonth);
	Timer_month.SetText(time_tmp);
	time_tmp.Format(_T("%2d"), st.wDay);
	Timer_day.SetText(time_tmp);
	time_tmp.Format(_T("%2d"), st.wHour);
	Timer_hour.SetText(time_tmp);
	time_tmp.Format(_T("%2d"), st.wMinute);
	Timer_minute.SetText(time_tmp);
	time_tmp.Format(_T("%2d"), st.wSecond);
	Timer_second.SetText(time_tmp);
}


void CSerialAssistantDlg::OnClickedBtnPause()
{
	// 定时器暂停与恢复
	counterPause = !counterPause;
	if (counterPause) {
		BtnPause.SetWindowText(_T("恢复"));
	}
	else{
		BtnPause.SetWindowText(_T("暂停"));
	}
}


void CSerialAssistantDlg::OnClickedBtnSetzero()
{
	// 将定时器清零
	secCounter = 0;
	EditCounter.SetText(_T("0000"));
}

void CSerialAssistantDlg::SerialParaInit()
{
	OnSelchangeComboBdr();
	OnSelchangeComboCheckbit();
	OnSelchangeComboCom();
	OnSelchangeComboStopbit();
	OnCbnSelchangeComboComG();
	OnCbnSelchangeComboBdrG();
	OnCbnSelchangeComboStopbitG();
	OnCbnSelchangeComboCheckbitG();
}

DWORD WINAPI CSerialAssistantDlg::SerialThread(LPVOID lpara)
{
	static SerialPort* serialPort = (SerialPort *)lpara;
	static BOOL isGetPkgHead = FALSE;
	while (isRunningIMU)
	{
		isGetPkgHead = serialPort->findHead();
		if (isGetPkgHead)
		{
			serialPort->readPkg();
		}
	}
	isRunningIMU = 2;
	return 0;
}

DWORD WINAPI CSerialAssistantDlg::SerialThreadGPS(LPVOID lpara)
{
	static SerialPort* serialPort = (SerialPort*)lpara;
	static BOOL isGetPkgHead = FALSE;
	while (isRunningGPS)
	{
		isGetPkgHead = serialPort->findGPSHead();
		if (isGetPkgHead)
		{
			serialPort->readGPSPkg();
		}
	}
	isRunningIMU = 2;
	return 0;
}

/***********************  List操作  ***********************/
// 加入一行IMU数据
void MyListCtrl::AddIMUItem(IMUData imudata)
{
	nextRowNUm = InsertItem(nextRowNUm, _T(""));
	nextContent.Format(_T("%d"), imudata.counter);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), imudata.wx);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), imudata.wy);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), imudata.wz);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), imudata.fx);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), imudata.fy);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), imudata.fz);
	SetItemText(nextRowNUm, idx++, nextContent);
	idx = 0;
	if (nextRowNUm++ > 7)
	{
		nextRowNUm = 0;
		DeleteAllItems();
	}
}

// 加入一行IMU数据
void MyListCtrl::AddGPSItem(GPGGAPKG gpgga, BESTVELPKG bestvel)
{
	nextRowNUm = InsertItem(nextRowNUm, _T(""));
	nextContent.Format(_T("%.3f"), gpgga.time);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%.3f"), bestvel.vel_h);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%.3f"), bestvel.heading);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%.3f"), bestvel.vel_v);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), gpgga.Lat);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), gpgga.Lng);
	SetItemText(nextRowNUm, idx++, nextContent);
	nextContent.Format(_T("%f"), gpgga.Alt+gpgga.Herr);		// 修改为椭球高
	SetItemText(nextRowNUm, idx++, nextContent);
	idx = 0;
	if (nextRowNUm++ > 6)
	{
		nextRowNUm = 0;
		DeleteAllItems();
	}
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
	ON_BN_CLICKED(IDOK, &CAboutDlg::OnBnClickedOk)
END_MESSAGE_MAP()


void CAboutDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	CDialogEx::OnOK();
}


void CSerialAssistantDlg::OnAppAbout()
{
	// TODO: 在此添加命令处理程序代码
	CAboutDlg dlgAbout;
	dlgAbout.DoModal();
}


void CSerialAssistantDlg::OnCbnSelchangeComboComG()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = Comb_com_g.GetCurSel();
	CString lab, lab10("\\\\.\\");
	Comb_com_g.GetLBText(idx, lab);
	if (idx >= 9)
	{
		lab = lab10 + lab;
	}
	mySerial.ComNumG = lab;
	
}


void CSerialAssistantDlg::OnCbnSelchangeComboBdrG()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = Comb_bdr_g.GetCurSel();
	CString lab;
	Comb_bdr_g.GetLBText(idx, lab);
	mySerial.bdrG = _ttoi(lab);
}


void CSerialAssistantDlg::OnCbnSelchangeComboStopbitG()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = Comb_stp_g.GetCurSel();
	mySerial.stopbG = idx;
}


void CSerialAssistantDlg::OnCbnSelchangeComboCheckbitG()
{
	// TODO: 在此添加控件通知处理程序代码
	int idx = Comb_chk_g.GetCurSel();
	mySerial.checkbG = idx;
}


void CSerialAssistantDlg::OnBnClickedCheckGpgga()
{
	// TODO: 在此添加控件通知处理程序代码
	if (checkGPGGA.GetCheck())
		mySerial.pkgHeadPOS[1] = 'P';
	else
		mySerial.pkgHeadPOS[1] = 'N';
}
